package com.feign.coder;

import com.common.resp.Result;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

/**
 * @作者: 林江
 * @创建时间: 2023/10/29
 * @功能: 自定义feign解码器
 */
@Slf4j
@Component
public class CustomDecoder implements Decoder {

    SpringDecoder decoder;

    @Autowired
    public CustomDecoder() {
        ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(new MappingJackson2HttpMessageConverter());
        SpringDecoder springDecoder = new SpringDecoder(objectFactory);
        this.decoder = springDecoder;
    }

    /**
     * @param response 响应数据体
     * @param type     方法参数类型
     * @return 实际的对象类型
     */
    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        log.info("自定编码器。。。。。。。。。");
        String data = Util.toString(response.body().asReader(Charset.defaultCharset()));
        // 服务提供方返回的类型是Result类型的话就需要进行转换，然后返回data。
        if (data.indexOf("code") > 0 &&
                data.indexOf("data") > 0) {
            // 使用jackson转换具体将类型转换为具体的类型
            ObjectMapper mapper = new ObjectMapper();
            JavaType javaType = TypeFactory.defaultInstance().constructType(type);
            Result result = mapper.readValue(data, javaType);
            return result.getData();
        }

        return this.decoder.decode(response, type);
    }
}
